javascript tutorial - [Solved-5 Solutions] “Thinking in Angular JS” - javascript - java script - javascript array



Problem:

What happens if we have a jQuery background ?

Solution 1:

  • In jQuery, wedesign a page, and then wemake it dynamic. This is because jQuery was designed for augmentation and has grown incredibly from that simple premise.
  • But in AngularJS, wemust start from the ground up with wer architecture in mind. Instead of starting by thinking "WEhave this piece of the DOM and WEwant to make it do X", wehave to start with what wewant to accomplish, then go about designing wer application, and then finally go about designing wer view.

Solution 2:

  • Similarly, don't start with the idea that jQuery does X, Y, and Z, so we'll just add AngularJS on top of that for models and controllers. This is really tempting when we're just starting out, which is why WEalways recommend that new AngularJS developers don't use jQuery at all, at least until they get used to doing things the "Angular Way".
  • I've seen many developers here and on the mailing list create these elaborate solutions with jQuery plugins of 150 or 200 lines of code that they then glue into AngularJS with a collection of callbacks and $applys that are confusing and convoluted; but they eventually get it working! The problem is that in most cases that jQuery plugin could be rewritten in AngularJS in a fraction of the code, where suddenly everything becomes comprehensible and straightforward.
  • The bottom line is this: when solutioning, first "think in AngularJS"; if wecan't think of a solution, ask the community; if after all of that there is no easy solution, then feel free to reach for the jQuery. But don't let jQuery become a crutch or we'll never master AngularJS

Solution 3:

3. Always think in terms of architecture

  • First know that single-page applications are applications. They're not webpages. So weneed to think like a server-side developer in addition to thinking like a client-side developer. Wehave to think about how to divide our application into individual, extensible, testable components.
  • So then how do wedo that? How do we"think in AngularJS"? Here are some general principles, contrasted with jQuery.
  • The view is the "official record"
  • In jQuery, we programmatically change the view. We could have a dropdown menu defined as a ul like so:
<ul class="main-menu">
    <lweclass="active">
        <a href="#/home">Home</a>
    </li>
    <li>
        <a href="#/menu1">Menu 1</a>
        <ul>
            <li><a href="#/sm1">Submenu 1</a></li>
            <li><a href="#/sm2">Submenu 2</a></li>
            <li><a href="#/sm3">Submenu 3</a></li>
        </ul>
    </li>
    <li>
        <a href="#/home">Menu 2</a>
    </li>
</ul>
click below button to copy the code. By JavaScript tutorial team
  • In jQuery, in our application logic, we would activate it with something like:
$('.main-menu').dropdownMenu();
click below button to copy the code. By JavaScript tutorial team
  • When we just look at the view, it's not immediately obvious that there is any functionality here. For small applications, that's fine. But for non-trivial applications, things quickly get confusing and hard to maintain.
  • In AngularJS, though, the view is the official record of view-based functionality. Our ul declaration would look like this instead:
<ul class="main-menu" dropdown-menu>
    ...
</ul>
click below button to copy the code. By JavaScript tutorial team
  • These two do the same thing, but in the AngularJS version anyone looking at the template knows what's supposed to happen. Whenever a new member of the development team comes on board, she can look at this and then know that there is a directive called dropdownMenu operating on it; she doesn't need to intuit the right answer or sift through any code. The view told us what was supposed to happen. Much cleaner.
  • Developers new to AngularJS often ask a question like: how do We find all links of a specific kind and add a directive onto them. The developer is always flabbergasted when we reply: we don't. But the reason we don't do that is that this is like half-jQuery, half-AngularJS, and no good. The problem here is that the developer is trying to "do jQuery" in the context of AngularJS. That's never going to work well. The view is the official record. Outside of a directive (more on this below), we never, ever, never change the DOM. And directives are applied in the view, so intent is clear.
  • Remember: don't design, and then mark up. We must architect, and then design.
  • Data binding
  • This is by far one of the most awesome features of AngularJS and cuts out a lot of the need to do the kinds of DOM manipulations We mentioned in the previous section. AngularJS will automatically update wer view so we don't have to! In jQuery, we respond to events and then update content. Something like:
$.ajax({
  url: '/myEndpoint.json',
  success: function ( data, status ) {
    $('ul#log').append('<li>Data Received!</li>');
  }
});
click below button to copy the code. By JavaScript tutorial team
  • For a view that looks like this:
<ul class="messages" id="log">
</ul>
click below button to copy the code. By JavaScript tutorial team
  • Apart from mixing concerns, we also have the same problems of signifying intent that We mentioned before. But more importantly, we had to manually reference and update a DOM node. And if we want to delete a log entry, we have to code against the DOM for that too.
$http( '/myEndpoint.json' ).then( function ( response ) {
    $scope.log.push( { msg: 'Data Received!' } );
});
click below button to copy the code. By JavaScript tutorial team
  • And our view can look like this:
<ul class="messages">
    <lweng-repeat="entry in log">{{ entry.msg }}</li>
</ul>
But for that matter, our view could look like this:
<div class="messages">
    <div class="alert" ng-repeat="entry in log">
        {{ entry.msg }}
    </div>
</div>
click below button to copy the code. By JavaScript tutorial team
  • And now instead of using an unordered list, we're using Bootstrap alert boxes. And we never had to change the controller code! But more importantly, no matter where or how the log gets updated, the view will change too. Automatically. Neat!
  • Though We didn't show it here, the data binding is two-way. So those log messages could also be editable in the view just by doing this: . And there was much rejoicing.
  • Distinct model layer
  • In jQuery, the DOM is kind of like the model. But in AngularJS, we have a separate model layer that we can manage in any way we want, completely independently from the view. This helps for the above data binding, maintains separation of concerns, and introduces far greater testability. Other answers mentioned this point, so I'll just leave it at that.
  • Separation of concerns
  • And all of the above tie into this over-arching theme: keep were concerns separate. Were view acts as the official record of what is supposed to happen (for the most part); were model represents were data; we have a service layer to perform reusable tasks; we do DOM manipulation and augment were view with directives; and weglue it all together with controllers. This was also mentioned in other answers, and the only thing we would add pertains to testability, which we discuss in another section below.
  • Dependency injection
  • To help us out with separation of concerns is dependency injection (DI). If we come from a server-side language (from Java to PHP) we're probably familiar with this concept already, but if we're a client-side guy coming from jQuery, this concept can seem anything from silly to superfluous to hipster. But it's not. :-)
  • From a broad perspective, DWE means that we can declare components very freely and then from any other component, just ask for an instance of it and it will be granted. We don't have to know about loading order, or file locations, or anything like that. The power may not immediately be visible, but I'll provide just one (common) example: testing.
  • Let's say in our application, we require a service that implements server-side storage through a REST APWE and, depending on application state, local storage as well. When running tests on our controllers, we don't want to have to communicate with the server - we're testing the controller, after all. We can just add a mock service of the same name as our original component, and the injector will ensure that our controller gets the fake one automatically - our controller doesn't and needn't know the difference.

Solution 4:

4. Test-driven development - always

  • This is really part of section 3 on architecture, but it's so important that I'm putting it as its own top-level section.
  • Out of all of the many jQuery plugins we've seen, used, or written, how many of them had an accompanying test suite? Not very many because jQuery isn't very amenable to that. But AngularJS is.
  • In jQuery, the only way to test is often to create the component independently with a sample/demo page against which our tests can perform DOM manipulation. So then we have to develop a component separately and then integrate it into our application. How inconvenient! So much of the time, when developing with jQuery, we opt for iterative instead of test-driven development. And who could blame us?
  • But because we have separation of concerns, we can do test-driven development iteratively in AngularJS! For example, let's say we want a super-simple directive to indicate in our menu what our current route is. We can declare what we want in the view of our application:
<a href="/hello" when-active>Hello</a>
click below button to copy the code. By JavaScript tutorial team
  • Okay, now wecan write a test for the non-existent when-active directive:
it( 'should add "active" when the route changes', inject(function() {
    var elm = $compile( '<a href="/hello" when-active>Hello</a>' )( $scope );

    $location.path('/not-matching');
    expect( elm.hasClass('active') ).toBeFalsey();

    $location.path( '/hello' );
    expect( elm.hasClass('active') ).toBeTruthy();
}));
click below button to copy the code. By JavaScript tutorial team
  • And when werun our test, wecan confirm that it fails. Only now should wecreate our directive:
.directive( 'whenActive', function ( $location ) {
    return {
        scope: true,
        link: function ( scope, element, attrs ) {
            scope.$on( '$routeChangeSuccess', function () {
                if ( $location.path() == element.attr( 'href' ) ) {
                    element.addClass( 'active' );
                }
                else {
                    element.removeClass( 'active' );
                }
            });
        }
    };
});
click below button to copy the code. By JavaScript tutorial team
  • Our test now passes and our menu performs as requested. Our development is both iterative andtest-driven. Wicked-cool.

Solution 5:

5. Conceptually, directives are not packaged jQuery

  • We'll often hear "only do DOM manipulation in a directive". This is a necessity. Treat it with due deference!
  • But let's dive a little deeper...
  • Some directives just decorate what's already in the view (think ngClass) and therefore sometimes do DOM manipulation straight away and then are basically done. But if a directive is like a "widget" and has a template, it should also respect separation of concerns. That is, the template too should remain largely independent from its implementation in the link and controller functions.
  • better, it's often still wrong.
.directive( 'myDirective', function () {
    return {
        template: '<a class="btn">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            var on = false;

            $(element).click( function () {
                on = !on;
                $(element).toggleClass('active', on);
            });
        }
    };
});
click below button to copy the code. By JavaScript tutorial team

Related Searches to javascript tutorial - “Thinking in Angular JS”